InĀ [1]:
from google.colab import drive
drive.mount('/content/drive')
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
InĀ [2]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
%config InlineBackend.figure_format = 'svg'
%matplotlib inline
pd.set_option('expand_frame_repr', True)
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
pd.set_option('display.width', 180)
InĀ [3]:
class BinomialModelAmericanPut:
def __init__(self, S0, K, T, r, sigma, mu, N):
self.S0 = S0 # Initial stock price
self.K = K # Strike price
self.T = T # Time to maturity
self.r = r # Risk-free rate
self.sigma = sigma # Volatility
self.mu = mu # Expected return
self.N = N # Number of steps
self.dt = T / N # Time step size
self.u = np.exp(r * self.dt + sigma * np.sqrt(self.dt)) # Up factor
self.d = np.exp(r * self.dt - sigma * np.sqrt(self.dt)) # Down factor
# Risk-neutral probabilities
self.p = (np.exp(r * self.dt) - self.d) / (self.u - self.d)
self.q = 1 - self.p
# Practical probabilities
self.real_p = (1 + (self.mu - self.r - self.sigma ** 2 / 2) * np.sqrt(self.dt) / self.sigma) / 2
self.real_q = 1 - self.real_p
# In the trees below, the i stands for th time step and the j stands for the state
# Initialize the option value tree and delta tree
self.option_values = np.full((N + 1, N + 1), np.nan)
self.delta_values = np.full((N + 1, N), np.nan)
# Initialize the exercise status tree
self.exercise_status = np.full((N + 1, N), np.nan)
self.realized_exercise = np.full((N + 1, N), np.nan)
# Initialize the stock price tree
self.stock_prices = np.full((N + 1, N + 1), np.nan)
self._build_stock_price_tree()
# Calculate option values using backward induction
self._calculate_option_values()
def _build_stock_price_tree(self):
# Build the stock price tree
# For each cell in the triangular matrix, (i - j) is the multiple of Up's and (j) is the multiple of Down's
for i in range(self.N + 1):
for j in range(i + 1):
self.stock_prices[j, i] = self.S0 * (self.u ** (i - j)) * (self.d ** j)
def _calculate_option_values(self):
# Initialize the option values at maturity
for j in range(self.N + 1):
self.option_values[j, self.N] = max(0, self.K - self.stock_prices[j, self.N])
# Backward induction to calculate option values and deltas
for i in range(self.N - 1, -1, -1):
for j in range(i + 1):
# Calculate the value if we hold the option
hold_value = np.exp(-self.r * self.dt) * (self.p * self.option_values[j, i + 1] +
self.q * self.option_values[j + 1, i + 1])
# Calculate the value if we exercise the option
exercise_value = self.K - self.stock_prices[j, i]
# Determine the exercise status for this step
if exercise_value >= hold_value:
self.exercise_status[j, i] = 0
self.option_values[j, i] = exercise_value
else:
self.exercise_status[j, i] = 1
self.option_values[j, i] = hold_value
# Calculate the delta
self.delta_values[j, i] = (self.option_values[j, i + 1] - self.option_values[j + 1, i + 1]) / (
self.stock_prices[j, i + 1] - self.stock_prices[j + 1, i + 1])
self.realized_exercise = self.exercise_status
def get_early_exercise_prices(self):
"""
Returns the stock prices at time step `t` where early exercise is optimal.
"""
self.exercise_prices_js = np.nansum(self.exercise_status, axis=0).astype(int)
self.exercise_prices = self.stock_prices[self.exercise_prices_js, np.arange(len(self.exercise_prices_js))]
return self.exercise_prices_js, self.exercise_prices
def fetch_along_the_path(self, path):
"""
Given a path (a list of 1s and 0s, 1 for a Down and 0 for an Up), return the values we concern along the path.
"""
js_path = np.insert(np.array(path), 0, 0).cumsum().astype(int)
prices_path = self.stock_prices[js_path, np.arange(len(js_path))]
# values_path = self.option_values[js_path, np.arange(len(js_path))]
# exercise_path = self.exercise_status[js_path[:-1], np.arange(len(js_path)-1)]
delta_path = self.delta_values[js_path[:-1], np.arange(len(js_path)-1)]
return prices_path, delta_path
def fetch_path_result(self, path):
"""
Given a path (a list of 1s and 0s, 1 for a Down and 0 for an Up), return the PnL and stopping time of the path.
"""
js_path = np.insert(np.array(path), 0, 0).cumsum().astype(int)
exercise_path = self.realized_exercise[js_path[:-1], np.arange(len(js_path)-1)]
if len(np.where(exercise_path == 0)[0]) > 0:
stopping_time = np.where(exercise_path == 0)[0][0]
PnL = self.K - self.stock_prices[js_path[stopping_time], stopping_time]
else:
stopping_time = len(js_path) - 1
PnL = self.option_values[js_path[stopping_time], stopping_time]
return PnL, stopping_time
def gen_simulation_paths(self, num_paths):
"""
Generate num_paths paths of the binomial tree.
"""
return np.random.choice([0, 1], size=(num_paths, self.N), p=[self.real_q, self.real_p])
def override_realized_exercise(self, exercise_boundary):
first_constrain = np.where(~np.isnan(exercise_boundary))[0][0]
for i in range(first_constrain):
for j in range(i+1):
self.realized_exercise[j, i] = 1
self.realized_exercise[self.stock_prices[:,:-1] > exercise_boundary] = 1
self.realized_exercise[self.stock_prices[:,:-1] <= exercise_boundary] = 0
return self.realized_exercise
InĀ [4]:
S0 = 10 # Initial stock price
K = 10 # Strike price
T = 1 # Time to maturity (1 year)
r = 0.02 # Risk-free rate
sigma = 0.20 # Volatility
mu = 0.05 # Expected return
N = 5000 # Number of steps
tree = BinomialModelAmericanPut(S0, K, T, r, sigma, mu, N)
early_exercise_js, exercise_boundary = tree.get_early_exercise_prices()
first_constrain = np.nonzero(early_exercise_js - np.arange(1,N+1))[0][0]
# i)
# Plot the exercise boundary as a function of t
times = np.linspace(0, T, N + 1)
plt.figure(figsize=(8, 4))
plt.plot(times, np.append(exercise_boundary, np.nan), label="Exercise Boundary")
plt.xlim(0, T)
plt.xlabel("Time (t)")
plt.ylabel("Stock Price")
plt.title("Exercise Boundary for American Put")
plt.legend();
InĀ [5]:
# ii)
# First generate the path where the option is exercised early near t = 1/2
# We need to check if it's possible to early exercise at int(N/2)
# Make sure that the boundary condition is not eliminated by former early exercises
t_half = int(N/2) - 1
while early_exercise_js[t_half] - early_exercise_js[t_half-1] == 1:
t_half += 1
# First we find the lower boundary path for the option to be early exercised at t_half, the path after t_half is generated randomly
path_list_half_lower_bound = np.concatenate((np.diff(np.append(early_exercise_js[0:t_half]-1, early_exercise_js[t_half])), np.random.randint(0, 2, size=N-t_half))).astype(int)
prices_path_half_lower_bound, delta_path_half_lower_bound = tree.fetch_along_the_path(path_list_half_lower_bound)
# We can also find the upper boundary path for the option to be early exercised at t_half, the path after t_half is generated randomly
path_list_half_upper_bound = np.concatenate((np.zeros(t_half-early_exercise_js[t_half]), np.ones(early_exercise_js[t_half]), np.random.randint(0, 2, size=N-t_half))).astype(int)
prices_path_half_upper_bound, delta_path_half_upper_bound = tree.fetch_along_the_path(path_list_half_upper_bound)
# All the paths in between fits our requirement
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, prices_path_half_lower_bound, label=f'Lower Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.plot(times, prices_path_half_upper_bound, label=f'Upper Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.scatter(t_half/N*T, prices_path_half_lower_bound[t_half], color='red',label = 'Half Time Early Exercise Point')
plt.xlabel("Time (t)")
plt.ylabel("Stock Price")
plt.title("Sample Paths for American Put")
plt.legend();
InĀ [6]:
# iii)
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, np.append(delta_path_half_lower_bound, np.nan), label=f'Lower Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.plot(times, np.append(delta_path_half_upper_bound, np.nan), label=f'Upper Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.xlabel("Time (t)")
plt.ylabel("Hedging Delta")
plt.title("Hedging Delta for American Put")
plt.legend();
InĀ [7]:
# Now generate the path where the option is not early exercised
t_full = N
# As the upper boundary path is trivial, we only look at the lower boundary path
path_list_full_lower_bound = np.append(np.diff(early_exercise_js[0:t_full+1]-1),1)
prices_path_full_lower_bound, delta_path_full_lower_bound = tree.fetch_along_the_path(path_list_full_lower_bound)
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, prices_path_full_lower_bound, label='Lower Boundary Path (No Early Exercise)')
plt.xlabel("Time (t)")
plt.ylabel("Stock Price")
plt.title("Sample Paths for American Put")
plt.legend();
InĀ [8]:
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, np.append(delta_path_full_lower_bound, np.nan), label='Lower Boundary Path (No Early Exercise)')
plt.xlabel("Time (t)")
plt.ylabel("Hedging Delta")
plt.title("Hedging Delta for American Put")
plt.legend();
InĀ [9]:
# iv)
for sigma_new in [0.10, 0.20, 0.30]:
for r_new in [0.00, 0.02, 0.04]:
tree = BinomialModelAmericanPut(S0, K, T, r_new, sigma_new, mu, N)
early_exercise_js, exercise_boundary = tree.get_early_exercise_prices()
# Plot the exercise boundary as a function of t
times = np.linspace(0, T, N + 1)
plt.figure(figsize=(8, 4))
plt.plot(times, np.append(exercise_boundary, np.nan), label="Exercise Boundary")
plt.xlim(0, T)
plt.xlabel("Time (t)")
plt.ylabel("Stock Price")
plt.title(f"Exercise Boundary for American Put with sigma = {sigma_new}; r = {r_new}")
plt.legend()
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Exercise_boundary_plot-sigma={sigma_new}&r={r_new}.jpg')
# Generate the path where the option is exercised early near t = 1/2
t_half = int(N/2) - 1
while early_exercise_js[t_half] - early_exercise_js[t_half-1] == 1:
t_half += 1
path_list_half_lower_bound = np.concatenate((np.diff(np.append(early_exercise_js[0:t_half]-1, early_exercise_js[t_half])), np.random.randint(0, 2, size=N-t_half))).astype(int)
prices_path_half_lower_bound, delta_path_half_lower_bound = tree.fetch_along_the_path(path_list_half_lower_bound)
# Now generate the path where the option is not early exercised
t_full = N
path_list_full_lower_bound = np.append(np.diff(early_exercise_js[0:t_full+1]-1),1)
prices_path_full_lower_bound, delta_path_full_lower_bound = tree.fetch_along_the_path(path_list_full_lower_bound)
# Plot the price paths
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, prices_path_half_lower_bound, label=f'Lower Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.scatter(t_half/N*T, prices_path_half_lower_bound[t_half], color='red',label = 'Half Time Early Exercise Point')
plt.plot(times, prices_path_full_lower_bound, label='Lower Boundary Path (No Early Exercise)')
plt.xlabel("Time (t)")
plt.ylabel("Stock Price")
plt.title(f"Sample Paths for American Put with sigma = {sigma_new}; r = {r_new}")
plt.legend()
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Sample_prices_path_plot-sigma={sigma_new}&r={r_new}.jpg')
# Plot the hedging delta
plt.figure(figsize=(8, 4))
times = np.linspace(0, T, N + 1)
plt.plot(times, np.append(delta_path_half_lower_bound, np.nan), label=f'Lower Boundary Path (Early Exercise at t={t_half/N*T:.2f} years)')
plt.plot(times, np.append(delta_path_full_lower_bound, np.nan), label='Lower Boundary Path (No Early Exercise)')
plt.xlabel("Time (t)")
plt.ylabel("Hedging Delta")
plt.title(f"Hedging Delta for American Put with sigma = {sigma_new}; r = {r_new}")
plt.legend()
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Delta_path_plot-sigma={sigma_new}&r={r_new}.jpg')
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478261e40>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.1; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf478141840>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478319ae0>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf478260fa0>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478180940>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.1; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf47817d6c0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4781bb490>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4781bb760>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.1; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf478261000>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4782121d0>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.1; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4781effd0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478078460>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf4781eed70>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478078a60>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.1; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4781eec80>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4780af580>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4780af910>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.1; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf47807aaa0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf47810e1a0>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.1; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4780af730>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f7d83a0>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf49f7d86a0>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f7d8520>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.1; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49f7a6290>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f7f7790>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f7f7a90>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.1; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49f7a63e0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf478143670>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.2; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf478143f40>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4782b20e0>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf4782b1a80>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf47828d3c0>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.2; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4782b1ff0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4782d1c00>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4782d0f10>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.2; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4782d1360>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf47824e260>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.2; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf47824fa00>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf479b8d300>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf479b8c4c0>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf479b8cac0>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.2; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf479b8f640>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f8b6b60>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f8b5d20>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.2; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49f8b5240>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4782e9c90>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.2; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4782e9330>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f8ad7e0>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf479ba7700>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f8ad2d0>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.2; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf479ba5b70>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f755030>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f755300>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.2; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49fa91cf0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f78fa60>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.3; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49f78fac0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf487849de0>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf487849ff0>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf48784a4d0>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.3; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf487823e20>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4878a9060>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4878a9420>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.3; r = 0.0')
Out[9]:
<matplotlib.legend.Legend at 0x7bf48788b0a0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4878dfbb0>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.3; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4878dfdf0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf487729e70>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf48772a170>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf48772a650>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.3; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf48770bd60>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf48778d1b0>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf48778d480>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.3; r = 0.02')
Out[9]:
<matplotlib.legend.Legend at 0x7bf48776b1f0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf4877b7ca0>]
Out[9]:
(0.0, 1.0)
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Exercise Boundary for American Put with sigma = 0.3; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4877b7f40>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f5b5f60>]
Out[9]:
<matplotlib.collections.PathCollection at 0x7bf49f5b6260>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f5b6740>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Stock Price')
Out[9]:
Text(0.5, 1.0, 'Sample Paths for American Put with sigma = 0.3; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf4877f7fa0>
Out[9]:
<Figure size 800x400 with 0 Axes>
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f6192a0>]
Out[9]:
[<matplotlib.lines.Line2D at 0x7bf49f619660>]
Out[9]:
Text(0.5, 0, 'Time (t)')
Out[9]:
Text(0, 0.5, 'Hedging Delta')
Out[9]:
Text(0.5, 1.0, 'Hedging Delta for American Put with sigma = 0.3; r = 0.04')
Out[9]:
<matplotlib.legend.Legend at 0x7bf49f5eb3a0>
InĀ [10]:
# pd.DataFrame(tree.stock_prices).to_csv('/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/stock_prices.csv')
# pd.DataFrame(tree.option_values).to_csv('/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/option_values.csv')
# pd.DataFrame(tree.delta_values).to_csv('/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/delta_values.csv')
# pd.DataFrame(tree.exercise_status).to_csv('/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/exercise_status.csv')
InĀ [11]:
# (b)
# i)
S0 = 10 # Initial stock price
K = 10 # Strike price
T = 1 # Time to maturity (1 year)
r = 0.02 # Risk-free rate
sigma = 0.20 # Volatility
mu = 0.05 # Expected return
N = 5000 # Number of steps
tree = BinomialModelAmericanPut(S0, K, T, r, sigma, mu, N)
# Simulate the paths
sample_paths = tree.gen_simulation_paths(10000)
# # Use the `path_list_half_lower_bound` and `path_list_full_lower_bound` before as examples
# PnL_early_exercise, stopping_time_early_exercise = tree.fetch_path_result(path_list_half_lower_bound)
# PnL_early_exercise, stopping_time_early_exercise
# PnL_no_early_exercise, stopping_time_no_early_exercise = tree.fetch_path_result(path_list_full_lower_bound)
# PnL_no_early_exercise, stopping_time_no_early_exercise
InĀ [12]:
# Get the PnL and stopping time for each path
PnL_distirbution = []
stopping_time_distribution = []
for path in sample_paths:
PnL_early_exercise, stopping_time_early_exercise = tree.fetch_path_result(path)
PnL_distirbution.append(PnL_early_exercise)
stopping_time_distribution.append(stopping_time_early_exercise / tree.N)
InĀ [13]:
# Plot the PnL histogram
PnL_continuous_part = [x for x in PnL_distirbution if x > 0] # All values less than 1
PnL_point_mass_count = len([x for x in PnL_distirbution if x == 0]) # Count the number of occurrences of 1
# Plot the histogram for the continuous part
plt.figure(figsize=(8, 6))
plt.hist(PnL_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
# Add the point mass at 1
plt.axvline(x=0, color='red', linestyle='--', linewidth=8, label='Point Mass at 0')
# Annotate the point mass with its relative probability
PnL_relative_mass_prob = PnL_point_mass_count / len(PnL_distirbution) # The probability mass at 1
plt.text(0., -0.05, f'Point Mass: {PnL_relative_mass_prob:.2f}', color='red')
plt.title("PnL Distribution with Point Mass at 0", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True);
InĀ [14]:
# Separate the continuous part and the point mass part
stopping_time_continuous_part = [x for x in stopping_time_distribution if x < 1] # All values less than 1
stopping_time_point_mass_count = len([x for x in stopping_time_distribution if x == 1]) # Count the number of occurrences of 1
# Plot the histogram for the continuous part
plt.figure(figsize=(8, 6))
plt.hist(stopping_time_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
# Add the point mass at 1
plt.axvline(x=1, color='red', linestyle='--', linewidth=2, label='Point Mass at 1')
# Annotate the point mass with its relative probability
stopping_time_relative_mass_prob = stopping_time_point_mass_count / len(stopping_time_distribution) # The probability mass at 1
plt.text(1+0.01, 0., f'Point Mass: {stopping_time_relative_mass_prob:.2f}', color='red')
plt.title("Stopping Time Distribution with Point Mass at 1", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True);
InĀ [15]:
# ii)
for sigma_new in [0.10, 0.20, 0.30]:
for r_new in [0.00, 0.02, 0.04]:
tree = BinomialModelAmericanPut(S0, K, T, r_new, sigma_new, mu, N)
sample_paths = tree.gen_simulation_paths(10000)
PnL_distirbution = []
stopping_time_distribution = []
for path in sample_paths:
PnL_early_exercise, stopping_time_early_exercise = tree.fetch_path_result(path)
PnL_distirbution.append(PnL_early_exercise)
stopping_time_distribution.append(stopping_time_early_exercise / tree.N)
# Plot the PnL histogram
PnL_continuous_part = [x for x in PnL_distirbution if x > 0]
PnL_point_mass_count = len([x for x in PnL_distirbution if x == 0])
plt.figure(figsize=(8, 6))
plt.hist(PnL_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
plt.axvline(x=0, color='red', linestyle='--', linewidth=8, label='Point Mass at 0')
PnL_relative_mass_prob = PnL_point_mass_count / len(PnL_distirbution)
plt.text(0., -0.05, f'Point Mass: {PnL_relative_mass_prob:.2f}', color='red')
plt.title(f"PnL Distribution of sigma = {sigma_new}; r = {r_new} with Point Mass at 0", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True)
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/PnL_distribution_plot-sigma={sigma_new}&r={r_new}.jpg')
# Separate the continuous part and the point mass part
stopping_time_continuous_part = [x for x in stopping_time_distribution if x < 1]
stopping_time_point_mass_count = len([x for x in stopping_time_distribution if x == 1])
plt.figure(figsize=(8, 6))
plt.hist(stopping_time_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
plt.axvline(x=1, color='red', linestyle='--', linewidth=2, label='Point Mass at 1')
stopping_time_relative_mass_prob = stopping_time_point_mass_count / len(stopping_time_distribution)
plt.text(1+0.01, 0., f'Point Mass: {stopping_time_relative_mass_prob:.2f}', color='red')
plt.title(f"Stopping Time Distribution of sigma = {sigma_new}; r = {r_new} with Point Mass at 1", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True)
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Stopping_time_distribution_plot-sigma={sigma_new}&r={r_new}.jpg')
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.57532829, 0.59036955, 0.67497665, 0.29706493, 0.86487259,
0.48884103, 0.79342659, 0.5659275 , 0.66557586, 0.56028703,
0.59977034, 0.6994187 , 0.64489413, 0.41927519, 0.49824182,
0.59224971, 0.33090777, 0.33654825, 0.32150698, 0.31398635,
0.30270541, 0.21809831, 0.21621815, 0.17109436, 0.09024757,
0.1692142 , 0.19741657, 0.11092931, 0.0488841 , 0.05640473,
0.03948331, 0.02444205, 0.05452458, 0.00940079, 0.02444205,
0.01692142, 0.00564047, 0.01504126, 0.00376032, 0.00376032,
0.00376032, 0.00188016, 0. , 0.00188016, 0. ,
0. , 0. , 0. , 0. , 0.00188016]),
array([0.02824431, 0.1074742 , 0.18670409, 0.26593398, 0.34516387,
0.42439376, 0.50362365, 0.58285354, 0.66208343, 0.74131332,
0.8205432 , 0.89977309, 0.97900298, 1.05823287, 1.13746276,
1.21669265, 1.29592254, 1.37515243, 1.45438232, 1.53361221,
1.6128421 , 1.69207199, 1.77130188, 1.85053177, 1.92976166,
2.00899155, 2.08822144, 2.16745133, 2.24668122, 2.32591111,
2.405141 , 2.48437089, 2.56360078, 2.64283066, 2.72206055,
2.80129044, 2.88052033, 2.95975022, 3.03898011, 3.11821 ,
3.19743989, 3.27666978, 3.35589967, 3.43512956, 3.51435945,
3.59358934, 3.67281923, 3.75204912, 3.83127901, 3.9105089 ,
3.98973879]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf492f79e40>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.33')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.1; r = 0.0 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf492d82e30>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([ 13.80542632, 15.77763008, 0. , 10.84712068,
13.80542632, 1.97220376, 0.49305094, 0.49305094,
2.4652547 , 0.49305094, 0. , 0. ,
1.47915282, 0. , 0. , 0. ,
3.45135658, 0. , 3.94440752, 0.49305094,
0. , 3.45135658, 0.98610188, 0.49305094,
0. , 3.45135658, 1.47915282, 0. ,
0. , 10.84712068, 11.34017162, 1.47915282,
1.97220376, 69.52018255, 1.47915282, 50.78424683,
2.4652547 , 62.61746939, 58.67306187, 228.77563618,
272.65716985, 151.3666386 , 167.63731962, 268.71276233,
30.56915828, 186.86630628, 305.69158283, 243.56716439,
464.94703647, 340.69819958]),
array([0.9832 , 0.983532, 0.983864, 0.984196, 0.984528, 0.98486 ,
0.985192, 0.985524, 0.985856, 0.986188, 0.98652 , 0.986852,
0.987184, 0.987516, 0.987848, 0.98818 , 0.988512, 0.988844,
0.989176, 0.989508, 0.98984 , 0.990172, 0.990504, 0.990836,
0.991168, 0.9915 , 0.991832, 0.992164, 0.992496, 0.992828,
0.99316 , 0.993492, 0.993824, 0.994156, 0.994488, 0.99482 ,
0.995152, 0.995484, 0.995816, 0.996148, 0.99648 , 0.996812,
0.997144, 0.997476, 0.997808, 0.99814 , 0.998472, 0.998804,
0.999136, 0.999468, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf492db6f20>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.39')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.1; r = 0.0 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf492db76a0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.54658811, 0.55512855, 0.23059186, 0.51242635, 0.4355624 ,
0.58074987, 0.23059186, 0.55512855, 0.29037493, 0.58074987,
0.35869845, 0.56366899, 0.25621318, 0.74301821, 0.40994108,
0.7173969 , 0.29037493, 0.8711248 , 0.30745581, 0.4782646 ,
0.61491163, 0.46118372, 0.96506963, 0.40140064, 1.1529593 ,
0.58929031, 1.13587842, 0.62345207, 0.54658811, 1.14441886,
0.76009909, 1.03339315, 1.23836369, 0.94798876, 0.94798876,
1.97284147, 0.98215051, 1.37501072, 1.25544457, 2.36570167,
2.00700322, 1.59706214, 2.07532674, 1.87889663, 2.12656937,
2.04970542, 2.14365025, 1.7849518 , 1.03339315, 0.21351098]),
array([0.02623968, 0.04754427, 0.06884885, 0.09015344, 0.11145802,
0.13276261, 0.15406719, 0.17537177, 0.19667636, 0.21798094,
0.23928553, 0.26059011, 0.2818947 , 0.30319928, 0.32450387,
0.34580845, 0.36711304, 0.38841762, 0.4097222 , 0.43102679,
0.45233137, 0.47363596, 0.49494054, 0.51624513, 0.53754971,
0.5588543 , 0.58015888, 0.60146346, 0.62276805, 0.64407263,
0.66537722, 0.6866818 , 0.70798639, 0.72929097, 0.75059556,
0.77190014, 0.79320472, 0.81450931, 0.83581389, 0.85711848,
0.87842306, 0.89972765, 0.92103223, 0.94233682, 0.9636414 ,
0.98494599, 1.00625057, 1.02755515, 1.04885974, 1.07016432,
1.09146891]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf492d83d30>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.45')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.1; r = 0.02 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49ed0c5b0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.04023364, 0.0905257 , 0.16093458, 0.14081776, 0.3621028 ,
0.44257009, 0.50292056, 0.57332944, 0.66385514, 0.78455607,
0.87508177, 0.79461449, 0.86502336, 0.91531542, 0.78455607,
1.03601635, 1.00584112, 1.07625 , 1.04607477, 0.93543224,
1.3478271 , 1.13660047, 1.07625 , 0.99578271, 1.00584112,
1.15671729, 1.11648364, 1.06619159, 1.22712617, 0.91531542,
1.24724299, 1.06619159, 0.97566589, 1.20700934, 1.01589953,
1.19695093, 1.05613318, 0.99578271, 1.21706776, 1.20700934,
1.00584112, 1.10642523, 1.33776869, 1.47858645, 1.3478271 ,
1.5288785 , 1.45846962, 1.86080607, 2.56489486, 5.95457943]),
array([0.0902 , 0.108392, 0.126584, 0.144776, 0.162968, 0.18116 ,
0.199352, 0.217544, 0.235736, 0.253928, 0.27212 , 0.290312,
0.308504, 0.326696, 0.344888, 0.36308 , 0.381272, 0.399464,
0.417656, 0.435848, 0.45404 , 0.472232, 0.490424, 0.508616,
0.526808, 0.545 , 0.563192, 0.581384, 0.599576, 0.617768,
0.63596 , 0.654152, 0.672344, 0.690536, 0.708728, 0.72692 ,
0.745112, 0.763304, 0.781496, 0.799688, 0.81788 , 0.836072,
0.854264, 0.872456, 0.890648, 0.90884 , 0.927032, 0.945224,
0.963416, 0.981608, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49ed0de70>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.45')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.1; r = 0.02 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49ed40880>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.65210709, 0.21264362, 0.34022979, 0.14176241, 0.22681986,
0.26934858, 0.22681986, 0.42528723, 0.28352482, 0.53869716,
0.29770106, 0.28352482, 0.29770106, 0.3118773 , 0.34022979,
0.51034468, 0.28352482, 0.4819922 , 0.49616844, 0.34022979,
0.63793085, 0.63793085, 0.58122588, 0.72298829, 0.73716454,
0.39693475, 0.52452092, 0.69463581, 0.92145567, 1.19080425,
0.56704964, 0.62375461, 1.68697269, 0.75134078, 1.38927162,
1.54521028, 1.87126382, 1.14827553, 2.28237481, 2.65095708,
1.19080425, 2.04137871, 3.2463592 , 4.08275743, 3.09042055,
4.05440494, 5.40114785, 5.67049643, 4.60727835, 1.29003794]),
array([0.02423466, 0.04005802, 0.05588139, 0.07170475, 0.08752812,
0.10335148, 0.11917485, 0.13499821, 0.15082158, 0.16664494,
0.18246831, 0.19829167, 0.21411504, 0.2299384 , 0.24576177,
0.26158513, 0.2774085 , 0.29323186, 0.30905523, 0.32487859,
0.34070196, 0.35652532, 0.37234869, 0.38817205, 0.40399542,
0.41981878, 0.43564215, 0.45146551, 0.46728888, 0.48311224,
0.49893561, 0.51475897, 0.53058234, 0.5464057 , 0.56222907,
0.57805243, 0.5938758 , 0.60969916, 0.62552253, 0.64134589,
0.65716926, 0.67299262, 0.68881599, 0.70463935, 0.72046272,
0.73628608, 0.75210945, 0.76793281, 0.78375618, 0.79957954,
0.81540291]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49ee3c5b0>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.55')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.1; r = 0.04 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf492e19360>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.10670518, 0.28454715, 0.42682073, 0.62837497, 0.75879241,
0.8654976 , 1.38716738, 1.20932541, 1.2448938 , 1.09076409,
1.16190088, 1.15004475, 1.31603059, 1.35159898, 1.22118154,
1.13818862, 1.23303767, 1.4345919 , 1.0551957 , 1.06705183,
1.06705183, 1.09076409, 0.91292212, 0.93663438, 0.91292212,
0.8654976 , 0.94849052, 1.10262022, 1.09076409, 1.09076409,
0.92477825, 0.93663438, 0.79436081, 0.85364146, 0.97220278,
1.0551957 , 0.94849052, 1.0551957 , 0.8654976 , 0.74693628,
1.00777117, 0.77064854, 0.98405891, 0.8654976 , 1.10262022,
0.96034665, 1.20932541, 1.31603059, 1.54129709, 3.43827812]),
array([0.0474 , 0.066448, 0.085496, 0.104544, 0.123592, 0.14264 ,
0.161688, 0.180736, 0.199784, 0.218832, 0.23788 , 0.256928,
0.275976, 0.295024, 0.314072, 0.33312 , 0.352168, 0.371216,
0.390264, 0.409312, 0.42836 , 0.447408, 0.466456, 0.485504,
0.504552, 0.5236 , 0.542648, 0.561696, 0.580744, 0.599792,
0.61884 , 0.637888, 0.656936, 0.675984, 0.695032, 0.71408 ,
0.733128, 0.752176, 0.771224, 0.790272, 0.80932 , 0.828368,
0.847416, 0.866464, 0.885512, 0.90456 , 0.923608, 0.942656,
0.961704, 0.980752, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf492e1ae60>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.56')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.1; r = 0.04 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf492e37bb0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.34476384, 0.37254102, 0.33986198, 0.39051449, 0.36273731,
0.34966569, 0.29901318, 0.47711393, 0.34312988, 0.45423861,
0.27613786, 0.47384603, 0.271236 , 0.35456755, 0.25326253,
0.32515641, 0.40685401, 0.39214844, 0.23692302, 0.20424398,
0.27450391, 0.12581429, 0.23365511, 0.13071615, 0.23692302,
0.19117236, 0.15522542, 0.08169759, 0.1830026 , 0.12581429,
0.07842969, 0.11110872, 0.07679574, 0.08006364, 0.07025993,
0.0408488 , 0.02777718, 0.02450928, 0.02941113, 0.01143766,
0.01960742, 0.02124137, 0.01143766, 0.00816976, 0.00490186,
0.00653581, 0. , 0.00163395, 0.00163395, 0.00163395]),
array([9.30810984e-13, 1.07597248e-01, 2.15194496e-01, 3.22791744e-01,
4.30388992e-01, 5.37986240e-01, 6.45583488e-01, 7.53180736e-01,
8.60777984e-01, 9.68375232e-01, 1.07597248e+00, 1.18356973e+00,
1.29116698e+00, 1.39876422e+00, 1.50636147e+00, 1.61395872e+00,
1.72155597e+00, 1.82915322e+00, 1.93675046e+00, 2.04434771e+00,
2.15194496e+00, 2.25954221e+00, 2.36713946e+00, 2.47473670e+00,
2.58233395e+00, 2.68993120e+00, 2.79752845e+00, 2.90512570e+00,
3.01272294e+00, 3.12032019e+00, 3.22791744e+00, 3.33551469e+00,
3.44311194e+00, 3.55070918e+00, 3.65830643e+00, 3.76590368e+00,
3.87350093e+00, 3.98109818e+00, 4.08869542e+00, 4.19629267e+00,
4.30388992e+00, 4.41148717e+00, 4.51908442e+00, 4.62668167e+00,
4.73427891e+00, 4.84187616e+00, 4.94947341e+00, 5.05707066e+00,
5.16466791e+00, 5.27226515e+00, 5.37986240e+00]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49ed0cfd0>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.43')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.2; r = 0.0 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f103b80>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([ 55.41450046, 28.21101842, 47.35420949, 0. ,
0. , 21.662032 , 0. , 89.16696893,
19.64695926, 0. , 11.08290009, 22.16580019,
0. , 0. , 5.54145005, 27.20348205,
0. , 2.51884093, 40.80522307, 0.50376819,
44.83536856, 82.11421432, 0. , 40.30145488,
72.0388506 , 67.00116874, 70.52754604, 4.53391367,
62.97102325, 21.15826381, 28.7147866 , 46.34667311,
35.76754121, 20.15072744, 64.986096 , 11.58666828,
123.42320558, 72.0388506 , 129.972192 , 63.47479144,
41.81275944, 32.74493209, 38.79015032, 181.35654697,
75.5652279 , 232.23713376, 155.1606013 , 267.50090678,
153.64929674, 165.7397332 ]),
array([0.9818 , 0.98216, 0.98252, 0.98288, 0.98324, 0.9836 , 0.98396,
0.98432, 0.98468, 0.98504, 0.9854 , 0.98576, 0.98612, 0.98648,
0.98684, 0.9872 , 0.98756, 0.98792, 0.98828, 0.98864, 0.989 ,
0.98936, 0.98972, 0.99008, 0.99044, 0.9908 , 0.99116, 0.99152,
0.99188, 0.99224, 0.9926 , 0.99296, 0.99332, 0.99368, 0.99404,
0.9944 , 0.99476, 0.99512, 0.99548, 0.99584, 0.9962 , 0.99656,
0.99692, 0.99728, 0.99764, 0.998 , 0.99836, 0.99872, 0.99908,
0.99944, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f100550>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.45')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.2; r = 0.0 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f0dca00>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.39611012, 0.337736 , 0.30437936, 0.13342657, 0.35441432,
0.32105768, 0.32522726, 0.32522726, 0.11257867, 0.25017481,
0.30437936, 0.36275348, 0.337736 , 0.17512237, 0.32522726,
0.3794318 , 0.3794318 , 0.34190558, 0.4419755 , 0.14593531,
0.36275348, 0.3794318 , 0.4002797 , 0.42529718, 0.41695802,
0.38777096, 0.36692306, 0.26268355, 0.43780592, 0.52953669,
0.51285837, 0.52119753, 0.54621501, 0.55038459, 0.54204543,
0.60041955, 0.67130242, 0.64211536, 0.64211536, 0.47950173,
0.53370627, 0.64628494, 0.74218528, 0.59624997, 0.57123249,
0.64211536, 0.46699299, 0.35024474, 0.19597027, 0.03752622]),
array([0.02623968, 0.07498609, 0.12373249, 0.17247889, 0.22122529,
0.26997169, 0.31871809, 0.36746449, 0.4162109 , 0.4649573 ,
0.5137037 , 0.5624501 , 0.6111965 , 0.6599429 , 0.70868931,
0.75743571, 0.80618211, 0.85492851, 0.90367491, 0.95242131,
1.00116772, 1.04991412, 1.09866052, 1.14740692, 1.19615332,
1.24489972, 1.29364613, 1.34239253, 1.39113893, 1.43988533,
1.48863173, 1.53737813, 1.58612453, 1.63487094, 1.68361734,
1.73236374, 1.78111014, 1.82985654, 1.87860294, 1.92734935,
1.97609575, 2.02484215, 2.07358855, 2.12233495, 2.17108135,
2.21982776, 2.26857416, 2.31732056, 2.36606696, 2.41481336,
2.46355976]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f0ac040>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.51')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.2; r = 0.02 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f223250>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.02393718, 0.02393718, 0.01196859, 0.13165448, 0.15559165,
0.20346601, 0.23937177, 0.25134036, 0.32315189, 0.37102625,
0.49071214, 0.49071214, 0.58646085, 0.67024097, 0.68220955,
0.69417814, 0.6343352 , 0.65827238, 0.78992685, 0.64630379,
0.89764415, 1.01733004, 0.86173838, 0.94551851, 0.81386403,
1.0532358 , 1.02929863, 1.01733004, 1.0532358 , 1.08914157,
1.13701592, 1.30457617, 1.10111016, 1.30457617, 1.08914157,
1.19685887, 1.20882746, 1.47213641, 1.25670181, 1.41229346,
1.59182229, 1.54394794, 1.31654475, 1.52001076, 1.86709983,
2.03466008, 2.03466008, 2.98017858, 3.63845096, 9.4073107 ]),
array([0.1418 , 0.15896, 0.17612, 0.19328, 0.21044, 0.2276 , 0.24476,
0.26192, 0.27908, 0.29624, 0.3134 , 0.33056, 0.34772, 0.36488,
0.38204, 0.3992 , 0.41636, 0.43352, 0.45068, 0.46784, 0.485 ,
0.50216, 0.51932, 0.53648, 0.55364, 0.5708 , 0.58796, 0.60512,
0.62228, 0.63944, 0.6566 , 0.67376, 0.69092, 0.70808, 0.72524,
0.7424 , 0.75956, 0.77672, 0.79388, 0.81104, 0.8282 , 0.84536,
0.86252, 0.87968, 0.89684, 0.914 , 0.93116, 0.94832, 0.96548,
0.98264, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f288790>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.51')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.2; r = 0.02 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f1ea4a0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.36895667, 0.1325938 , 0.36895667, 0.1441237 , 0.34589688,
0.16141854, 0.16718349, 0.35166183, 0.14988865, 0.25365771,
0.19600823, 0.2767175 , 0.19600823, 0.40354636, 0.20177318,
0.24212782, 0.41507625, 0.16141854, 0.43813605, 0.28248245,
0.44966594, 0.20753813, 0.39778141, 0.44390099, 0.24789276,
0.65143912, 0.32283709, 0.65143912, 0.40354636, 0.34013193,
0.66873397, 0.34589688, 0.43813605, 1.1529896 , 0.51308037,
0.49002058, 1.02616074, 0.61684943, 0.69755871, 0.66873397,
1.21640402, 1.13569475, 0.997336 , 0.95698137, 1.08381022,
1.22793392, 1.12416486, 0.90509683, 0.36895667, 0.09800412]),
array([0.05241052, 0.09224108, 0.13207164, 0.1719022 , 0.21173277,
0.25156333, 0.29139389, 0.33122446, 0.37105502, 0.41088558,
0.45071615, 0.49054671, 0.53037727, 0.57020784, 0.6100384 ,
0.64986896, 0.68969953, 0.72953009, 0.76936065, 0.80919122,
0.84902178, 0.88885234, 0.92868291, 0.96851347, 1.00834403,
1.0481746 , 1.08800516, 1.12783572, 1.16766629, 1.20749685,
1.24732741, 1.28715798, 1.32698854, 1.3668191 , 1.40664966,
1.44648023, 1.48631079, 1.52614135, 1.56597192, 1.60580248,
1.64563304, 1.68546361, 1.72529417, 1.76512473, 1.8049553 ,
1.84478586, 1.88461642, 1.92444699, 1.96427755, 2.00410811,
2.04393868]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f221c30>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.56')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.2; r = 0.04 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f387e80>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.03788463, 0.08839747, 0.11365389, 0.15153853, 0.30307705,
0.37884631, 0.45461558, 0.50512842, 0.74506442, 0.71980799,
0.71980799, 0.61878231, 0.82083368, 1.04814147, 0.88397473,
0.99762862, 0.89660294, 0.88397473, 1.02288504, 0.87134652,
0.93448757, 0.89660294, 1.07339789, 0.85871831, 1.03551326,
0.99762862, 1.03551326, 1.12391073, 0.9723722 , 0.98500041,
1.2123082 , 1.03551326, 0.95974399, 0.83346189, 1.14916715,
1.12391073, 1.22493641, 1.47750062, 1.25019283, 1.02288504,
1.02288504, 1.36384673, 1.38910315, 1.31333388, 1.60378272,
1.55326988, 1.74269304, 2.03314188, 2.79083451, 6.20045132]),
array([0.082 , 0.100356, 0.118712, 0.137068, 0.155424, 0.17378 ,
0.192136, 0.210492, 0.228848, 0.247204, 0.26556 , 0.283916,
0.302272, 0.320628, 0.338984, 0.35734 , 0.375696, 0.394052,
0.412408, 0.430764, 0.44912 , 0.467476, 0.485832, 0.504188,
0.522544, 0.5409 , 0.559256, 0.577612, 0.595968, 0.614324,
0.63268 , 0.651036, 0.669392, 0.687748, 0.706104, 0.72446 ,
0.742816, 0.761172, 0.779528, 0.797884, 0.81624 , 0.834596,
0.852952, 0.871308, 0.889664, 0.90802 , 0.926376, 0.944732,
0.963088, 0.981444, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f1cbf70>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.57')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.2; r = 0.04 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf479ba63b0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.28885721, 0.25419434, 0.26904986, 0.27565231, 0.33012252,
0.14690452, 0.24264005, 0.3796409 , 0.38294213, 0.16506126,
0.34992987, 0.29711027, 0.21127841, 0.28225476, 0.26739924,
0.16176004, 0.35983355, 0.30701395, 0.16671187, 0.21953148,
0.23768822, 0.25749557, 0.22613393, 0.19477229, 0.23768822,
0.12049472, 0.18651923, 0.183218 , 0.09573553, 0.18982045,
0.1171935 , 0.10398859, 0.15020575, 0.0660245 , 0.08088002,
0.08253063, 0.06107267, 0.06932573, 0.07097634, 0.05447022,
0.03466286, 0.0264098 , 0.0264098 , 0.01155429, 0.0132049 ,
0.01650613, 0.00660245, 0.00330123, 0. , 0.00495184]),
array([0.08449383, 0.20515419, 0.32581455, 0.44647491, 0.56713527,
0.68779563, 0.80845599, 0.92911635, 1.04977672, 1.17043708,
1.29109744, 1.4117578 , 1.53241816, 1.65307852, 1.77373888,
1.89439924, 2.0150596 , 2.13571996, 2.25638032, 2.37704068,
2.49770104, 2.61836141, 2.73902177, 2.85968213, 2.98034249,
3.10100285, 3.22166321, 3.34232357, 3.46298393, 3.58364429,
3.70430465, 3.82496501, 3.94562537, 4.06628573, 4.18694609,
4.30760646, 4.42826682, 4.54892718, 4.66958754, 4.7902479 ,
4.91090826, 5.03156862, 5.15222898, 5.27288934, 5.3935497 ,
5.51421006, 5.63487042, 5.75553078, 5.87619114, 5.99685151,
6.11751187]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f1cb910>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.50')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.3; r = 0.0 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf487821b70>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([1.17308328e-01, 5.86541638e-02, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.17308328e-01,
0.00000000e+00, 0.00000000e+00, 1.75962491e-01, 5.86541638e-02,
3.51924983e-01, 0.00000000e+00, 1.17308328e-01, 4.69233310e-01,
2.34616655e-01, 1.75962491e-01, 5.86541638e-02, 4.69233310e-01,
3.51924983e-01, 2.93270819e-01, 7.62504129e-01, 5.86541638e-01,
8.21158293e-01, 1.17308328e+00, 7.62504129e-01, 1.87693324e+00,
4.69233310e-01, 2.11154990e+00, 2.05289573e+00, 1.40769993e+00,
1.64231659e+00, 2.46347488e+00, 3.57790399e+00, 3.34328734e+00,
2.75674570e+00, 5.74810805e+00, 5.63079972e+00, 4.98560392e+00,
6.39330385e+00, 9.32601204e+00, 8.56350791e+00, 1.40769993e+01,
1.09096745e+01, 1.99424157e+01, 2.19953114e+01, 2.18193489e+01,
4.63367894e+01, 7.44321338e+01]),
array([0.8206 , 0.824184, 0.827768, 0.831352, 0.834936, 0.83852 ,
0.842104, 0.845688, 0.849272, 0.852856, 0.85644 , 0.860024,
0.863608, 0.867192, 0.870776, 0.87436 , 0.877944, 0.881528,
0.885112, 0.888696, 0.89228 , 0.895864, 0.899448, 0.903032,
0.906616, 0.9102 , 0.913784, 0.917368, 0.920952, 0.924536,
0.92812 , 0.931704, 0.935288, 0.938872, 0.942456, 0.94604 ,
0.949624, 0.953208, 0.956792, 0.960376, 0.96396 , 0.967544,
0.971128, 0.974712, 0.978296, 0.98188 , 0.985464, 0.989048,
0.992632, 0.996216, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f2aa710>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.52')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.3; r = 0.0 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f2aaad0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.27146179, 0.27146179, 0.23566463, 0.24461392, 0.05966193,
0.20881676, 0.22373225, 0.25952941, 0.29830966, 0.10142529,
0.25058012, 0.2625125 , 0.24163083, 0.21776605, 0.27444489,
0.2684787 , 0.24759702, 0.2684787 , 0.22969844, 0.23566463,
0.23268154, 0.28041108, 0.25952941, 0.25952941, 0.24759702,
0.28936037, 0.28936037, 0.28339418, 0.30427586, 0.30725895,
0.51905881, 0.29830966, 0.30427586, 0.32217444, 0.32217444,
0.49221094, 0.34603921, 0.27444489, 0.33112373, 0.5309912 ,
0.31322515, 0.32217444, 0.51309262, 0.30725895, 0.25952941,
0.34305611, 0.19091818, 0.17003651, 0.05966193, 0.03878026]),
array([0.05440988, 0.12749079, 0.2005717 , 0.27365261, 0.34673352,
0.41981442, 0.49289533, 0.56597624, 0.63905715, 0.71213806,
0.78521897, 0.85829988, 0.93138079, 1.0044617 , 1.0775426 ,
1.15062351, 1.22370442, 1.29678533, 1.36986624, 1.44294715,
1.51602806, 1.58910897, 1.66218987, 1.73527078, 1.80835169,
1.8814326 , 1.95451351, 2.02759442, 2.10067533, 2.17375624,
2.24683715, 2.31991805, 2.39299896, 2.46607987, 2.53916078,
2.61224169, 2.6853226 , 2.75840351, 2.83148442, 2.90456532,
2.97764623, 3.05072714, 3.12380805, 3.19688896, 3.26996987,
3.34305078, 3.41613169, 3.4892126 , 3.5622935 , 3.63537441,
3.70845532]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49fc08bb0>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.54')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.3; r = 0.02 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f41c8e0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([ 0.01320504, 0.02641007, 0.05282015, 0.09243526, 0.09243526,
0.1056403 , 0.11884534, 0.11884534, 0.17166549, 0.26410075,
0.35653601, 0.43576623, 0.27730579, 0.46217631, 0.48858638,
0.44897127, 0.62063676, 0.46217631, 0.6338418 , 0.69986698,
0.71307202, 0.83191736, 0.89794254, 0.93755766, 0.67345691,
0.72627706, 0.95076269, 0.91114758, 1.21486344, 0.97717277,
0.85832743, 1.12242818, 1.18845337, 1.2016584 , 1.06960803,
1.3072987 , 1.3072987 , 1.25447855, 1.43934908, 1.76947501,
1.50537427, 1.82229516, 1.78268005, 1.82229516, 1.80909013,
2.45613696, 2.3637017 , 3.20882409, 4.29163716, 11.58081781]),
array([0.1656 , 0.182284, 0.198968, 0.215652, 0.232336, 0.24902 ,
0.265704, 0.282388, 0.299072, 0.315756, 0.33244 , 0.349124,
0.365808, 0.382492, 0.399176, 0.41586 , 0.432544, 0.449228,
0.465912, 0.482596, 0.49928 , 0.515964, 0.532648, 0.549332,
0.566016, 0.5827 , 0.599384, 0.616068, 0.632752, 0.649436,
0.66612 , 0.682804, 0.699488, 0.716172, 0.732856, 0.74954 ,
0.766224, 0.782908, 0.799592, 0.816276, 0.83296 , 0.849644,
0.866328, 0.883012, 0.899696, 0.91638 , 0.933064, 0.949748,
0.966432, 0.983116, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f83d180>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.55')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.3; r = 0.02 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f3d1f00>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.28828793, 0.27331194, 0.11980797, 0.14975996, 0.12355197,
0.26582394, 0.10483198, 0.24710394, 0.09359998, 0.28454393,
0.28079993, 0.08985598, 0.26956794, 0.13478397, 0.28828793,
0.22089595, 0.07862398, 0.33695992, 0.17222396, 0.25459194,
0.37439991, 0.13852797, 0.34444792, 0.30700793, 0.20591995,
0.25833594, 0.26582394, 0.37814391, 0.21340795, 0.39686391,
0.4268159 , 0.22463995, 0.4305599 , 0.46425589, 0.47174389,
0.19468795, 0.61027186, 0.54287987, 0.26956794, 0.59529586,
0.53913587, 0.47548789, 0.52790388, 0.71884783, 0.53913587,
0.49420788, 0.55785587, 0.25833594, 0.33695992, 0.10108798]),
array([0.02423466, 0.08776798, 0.1513013 , 0.21483462, 0.27836794,
0.34190126, 0.40543458, 0.4689679 , 0.53250122, 0.59603454,
0.65956786, 0.72310118, 0.7866345 , 0.85016782, 0.91370114,
0.97723446, 1.04076778, 1.10430111, 1.16783443, 1.23136775,
1.29490107, 1.35843439, 1.42196771, 1.48550103, 1.54903435,
1.61256767, 1.67610099, 1.73963431, 1.80316763, 1.86670095,
1.93023427, 1.99376759, 2.05730091, 2.12083423, 2.18436756,
2.24790088, 2.3114342 , 2.37496752, 2.43850084, 2.50203416,
2.56556748, 2.6291008 , 2.69263412, 2.75616744, 2.81970076,
2.88323408, 2.9467674 , 3.01030072, 3.07383404, 3.13736736,
3.20090068]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f3d19c0>
Out[15]:
Text(0.0, -0.05, 'Point Mass: 0.58')
Out[15]:
Text(0.5, 1.0, 'PnL Distribution of sigma = 0.3; r = 0.04 with Point Mass at 0')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf49f3aaaa0>
Out[15]:
<Figure size 800x600 with 0 Axes>
Out[15]:
(array([0.04069898, 0.09496428, 0.16279591, 0.12209694, 0.21706122,
0.20349489, 0.33915815, 0.35272448, 0.27132652, 0.50195407,
0.44768876, 0.63761733, 0.54265304, 0.58335202, 0.624051 ,
0.84111222, 0.69188263, 0.80041324, 0.80041324, 0.80041324,
0.96320915, 0.99034181, 0.82754589, 1.03104079, 0.96320915,
0.89537752, 0.85467855, 0.81397957, 1.08530609, 0.96320915,
1.01747446, 1.05817344, 1.04460711, 1.32949996, 1.1938367 ,
0.92251018, 1.28880098, 1.20740302, 1.37019894, 1.1938367 ,
1.5601275 , 1.45159689, 1.45159689, 1.41089792, 1.57369383,
1.8178877 , 2.21131116, 2.71326522, 3.21521929, 8.89950994]),
array([0.1132 , 0.130932, 0.148664, 0.166396, 0.184128, 0.20186 ,
0.219592, 0.237324, 0.255056, 0.272788, 0.29052 , 0.308252,
0.325984, 0.343716, 0.361448, 0.37918 , 0.396912, 0.414644,
0.432376, 0.450108, 0.46784 , 0.485572, 0.503304, 0.521036,
0.538768, 0.5565 , 0.574232, 0.591964, 0.609696, 0.627428,
0.64516 , 0.662892, 0.680624, 0.698356, 0.716088, 0.73382 ,
0.751552, 0.769284, 0.787016, 0.804748, 0.82248 , 0.840212,
0.857944, 0.875676, 0.893408, 0.91114 , 0.928872, 0.946604,
0.964336, 0.982068, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[15]:
<matplotlib.lines.Line2D at 0x7bf49f129420>
Out[15]:
Text(1.01, 0.0, 'Point Mass: 0.58')
Out[15]:
Text(0.5, 1.0, 'Stopping Time Distribution of sigma = 0.3; r = 0.04 with Point Mass at 1')
Out[15]:
Text(0.5, 0, 'Value')
Out[15]:
Text(0, 0.5, 'Density')
Out[15]:
<matplotlib.legend.Legend at 0x7bf4780d8f10>
InĀ [16]:
# iii)
# First we get the exercise boundary of the Put assuming sigma = 0.20
S0 = 10 # Initial stock price
K = 10 # Strike price
T = 1 # Time to maturity (1 year)
r = 0.02 # Risk-free rate
sigma = 0.20 # Volatility
mu = 0.05 # Expected return
N = 5000 # Number of steps
tree = BinomialModelAmericanPut(S0, K, T, r, sigma, mu, N)
early_exercise_js, exercise_boundary = tree.get_early_exercise_prices()
# Then we calculate the price paths for all possible realized volatilities
for sigma_new in [0.10]:#, 0.15, 0.20, 0.25, 0.30]:
tree = BinomialModelAmericanPut(S0, K, T, r, sigma_new, mu, N)
realized_exercise = tree.override_realized_exercise(exercise_boundary)
sample_paths = tree.gen_simulation_paths(10000)
PnL_distirbution = []
stopping_time_distribution = []
for path in sample_paths:
PnL_early_exercise, stopping_time_early_exercise = tree.fetch_path_result(path)
PnL_distirbution.append(PnL_early_exercise)
stopping_time_distribution.append(stopping_time_early_exercise / tree.N)
# Plot the PnL histogram
PnL_continuous_part = [x for x in PnL_distirbution if x > 0]
PnL_point_mass_count = len([x for x in PnL_distirbution if x == 0])
plt.figure(figsize=(8, 6))
plt.hist(PnL_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
plt.axvline(x=0, color='red', linestyle='--', linewidth=8, label='Point Mass at 0')
PnL_relative_mass_prob = PnL_point_mass_count / len(PnL_distirbution)
plt.text(-0.55, 0., f'Point Mass: {PnL_relative_mass_prob:.2f}', color='red')
plt.title(f"PnL Distribution of Miss-matched realized sigma = {sigma_new} with Point Mass at 0", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True)
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Miss-match-vol_PnL_distribution_plot-sigma={sigma_new}.jpg')
# Separate the continuous part and the point mass part
stopping_time_continuous_part = [x for x in stopping_time_distribution if x < 1]
stopping_time_point_mass_count = len([x for x in stopping_time_distribution if x == 1])
plt.figure(figsize=(8, 6))
plt.hist(stopping_time_continuous_part, bins=50, density=True, alpha=0.7, color='blue', label='Continuous Part')
plt.axvline(x=1, color='red', linestyle='--', linewidth=2, label='Point Mass at 1')
stopping_time_relative_mass_prob = stopping_time_point_mass_count / len(stopping_time_distribution)
plt.text(1+0.01, 0., f'Point Mass: {stopping_time_relative_mass_prob:.2f}', color='red')
plt.title(f"Stopping Time Distribution of Miss-matched realized sigma = {sigma_new} with Point Mass at 1", fontsize=15)
plt.xlabel("Value", fontsize=12)
plt.ylabel("Density", fontsize=12)
plt.legend()
plt.grid(True)
# plt.savefig(f'/content/drive/My Drive/SyncWorkspace/MMF/MMF1928H/Project 1/Miss-match-vol_Stopping_time_distribution_plot-sigma={sigma_new}.jpg')
Out[16]:
<Figure size 800x600 with 0 Axes>
Out[16]:
(array([0.98652503, 0.74993758, 0.76332932, 0.80350455, 0.38836053,
0.74547366, 0.77672106, 0.82582412, 0.46871099, 0.9775972 ,
0.62048407, 0.78564889, 0.90617457, 0.40621619, 0.83475195,
0.42853576, 0.77672106, 0.72761801, 0.55352536, 0.5669171 ,
0.49549447, 0.58030884, 0.66958712, 0.66512321, 0.30801008,
0.62494798, 0.37050487, 0.54906144, 0.5044223 , 0.50888621,
0.20087614, 0.54013361, 0.29461833, 0.42853576, 0.43299967,
0.29461833, 0.14730917, 0.27229876, 0.16070091, 0.20980397,
0.17409265, 0.21426788, 0.14730917, 0.04910306, 0.10267003,
0.05356697, 0.04017523, 0.04463914, 0.02231957, 0.01339174]),
array([0.02623968, 0.06932019, 0.1124007 , 0.15548121, 0.19856172,
0.24164223, 0.28472274, 0.32780324, 0.37088375, 0.41396426,
0.45704477, 0.50012528, 0.54320579, 0.5862863 , 0.6293668 ,
0.67244731, 0.71552782, 0.75860833, 0.80168884, 0.84476935,
0.88784986, 0.93093036, 0.97401087, 1.01709138, 1.06017189,
1.1032524 , 1.14633291, 1.18941342, 1.23249393, 1.27557443,
1.31865494, 1.36173545, 1.40481596, 1.44789647, 1.49097698,
1.53405749, 1.57713799, 1.6202185 , 1.66329901, 1.70637952,
1.74946003, 1.79254054, 1.83562105, 1.87870155, 1.92178206,
1.96486257, 2.00794308, 2.05102359, 2.0941041 , 2.13718461,
2.18026512]),
<BarContainer object of 50 artists>)
Out[16]:
<matplotlib.lines.Line2D at 0x7bf47810ce20>
Out[16]:
Text(-0.55, 0.0, 'Point Mass: 0.48')
Out[16]:
Text(0.5, 1.0, 'PnL Distribution of Miss-matched realized sigma = 0.1 with Point Mass at 0')
Out[16]:
Text(0.5, 0, 'Value')
Out[16]:
Text(0, 0.5, 'Density')
Out[16]:
<matplotlib.legend.Legend at 0x7bf47807b1c0>
Out[16]:
<Figure size 800x600 with 0 Axes>
Out[16]:
(array([1.75239696e-02, 1.75239696e-02, 1.75239696e-02, 0.00000000e+00,
1.75239696e-02, 5.25719089e-02, 1.75239696e-02, 7.00958785e-02,
5.25719089e-02, 5.25719089e-02, 1.75239696e-02, 8.76198482e-02,
5.25719089e-02, 1.57715727e-01, 5.25719089e-02, 1.92763666e-01,
1.75239696e-01, 1.22667787e-01, 1.92763666e-01, 1.92763666e-01,
2.27811605e-01, 4.03051302e-01, 3.32955423e-01, 3.32955423e-01,
3.15431453e-01, 3.85527332e-01, 3.68003362e-01, 5.43243059e-01,
4.90671150e-01, 6.65910846e-01, 5.60767028e-01, 7.88578634e-01,
5.08195119e-01, 1.15658200e+00, 1.33182169e+00, 8.93722451e-01,
1.62972918e+00, 1.69982505e+00, 1.45448948e+00, 1.84001681e+00,
1.48953742e+00, 2.19049620e+00, 3.08421866e+00, 2.92650293e+00,
3.45222202e+00, 4.22327668e+00, 4.94175944e+00, 7.34254328e+00,
1.08823851e+01, 2.99134162e+01]),
array([0.4312 , 0.442572, 0.453944, 0.465316, 0.476688, 0.48806 ,
0.499432, 0.510804, 0.522176, 0.533548, 0.54492 , 0.556292,
0.567664, 0.579036, 0.590408, 0.60178 , 0.613152, 0.624524,
0.635896, 0.647268, 0.65864 , 0.670012, 0.681384, 0.692756,
0.704128, 0.7155 , 0.726872, 0.738244, 0.749616, 0.760988,
0.77236 , 0.783732, 0.795104, 0.806476, 0.817848, 0.82922 ,
0.840592, 0.851964, 0.863336, 0.874708, 0.88608 , 0.897452,
0.908824, 0.920196, 0.931568, 0.94294 , 0.954312, 0.965684,
0.977056, 0.988428, 0.9998 ]),
<BarContainer object of 50 artists>)
Out[16]:
<matplotlib.lines.Line2D at 0x7bf49f086ad0>
Out[16]:
Text(1.01, 0.0, 'Point Mass: 0.50')
Out[16]:
Text(0.5, 1.0, 'Stopping Time Distribution of Miss-matched realized sigma = 0.1 with Point Mass at 1')
Out[16]:
Text(0.5, 0, 'Value')
Out[16]:
Text(0, 0.5, 'Density')
Out[16]:
<matplotlib.legend.Legend at 0x7bf49f7f6a70>
InĀ [16]: